﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Web;
using VDS.RDF;
using VDS.RDF.Parsing;
using VDS.RDF.Writing;
using VDS.RDF.Nodes;
using System.Data;

namespace Filmi.NonSemantic
{
    public class PageController
    {
        private static int ComputeLevenshteinDistance(string first, string second)
        {
            var n = first.Length;
            var m = second.Length;
            var d = new int[n + 1, m + 1];

            if (n == 0) return m;

            if (m == 0) return n;

            for (var i = 0; i <= n; d[i, 0] = i++)
            {
            }
            for (var j = 0; j <= m; d[0, j] = j++)
            {
            }

            for (var i = 1; i <= n; i++)
            {
                for (var j = 1; j <= m; j++)
                {
                    var cost = (second[j - 1] == first[i - 1]) ? 0 : 1;
                    d[i, j] = Math.Min(
                        Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
                        d[i - 1, j - 1] + cost);
                }
            }
            return d[n, m];
        }

        public string GetFilePathIfMovieExists(string searchString, string serverMapPath)
        {
            if (!Directory.Exists(serverMapPath)) return null;

            var fileNames = Directory.GetFiles(serverMapPath);
            searchString = searchString.Replace(":", "");
            searchString = searchString.Replace("?", "");
            var listOfMatcingWords = new List<string>();
            foreach (var fileName in fileNames)
            {
                var file = fileName.Split(new string[] {"\\"}, StringSplitOptions.None).Last();

                if (file.ToLower().IndexOf(searchString.ToLower(), System.StringComparison.CurrentCultureIgnoreCase) >=
                    0)
                {
                    listOfMatcingWords.Add(file);
                }
            }

            var min = 100;
            var selectedFile = "";
            foreach (var word in listOfMatcingWords)
            {
                var choosen = word.Substring(0, word.IndexOf(".", System.StringComparison.Ordinal));
                if (ComputeLevenshteinDistance(searchString, choosen) < min)
                {
                    min = ComputeLevenshteinDistance(searchString, choosen);
                    selectedFile = word;
                }
            }

            if (selectedFile != "")
                return serverMapPath + "\\" + selectedFile;
            return null;
        }

        public DataContainer GetMovieData(String name)
        {
            try
            {
                var nonSemanticController = new NonSemanticController();
                var movieData = nonSemanticController.GetMovieData(name);
                return movieData;
            }
            catch (Exception exc)
            {
                Console.WriteLine(exc.Message);
                return null;
            }
        }

        public IGraph ReadRDFFromFile(String fileName)
        {
            try
            {
                var g = new Graph();
                g.LoadFromFile(fileName);
                return g;
            }
            catch (RdfParseException parseEx)
            {
                //This indicates a parser error e.g unexpected character, premature end of input, invalid syntax etc.
                Console.WriteLine("Parser Error");
                Console.WriteLine(parseEx.Message);
                return null;
            }
            catch (RdfException rdfEx)
            {
                //This represents a RDF error e.g. illegal triple for the given syntax, undefined namespace
                Console.WriteLine("RDF Error");
                Console.WriteLine(rdfEx.Message);
                return null;
            }
        }

        public IGraph ReadOntologyFromFile(String fileName)
        {
            try
            {
                var g = new Graph();
                g.LoadFromFile(fileName, new TurtleParser());
                return g;
            }
            catch (RdfParseException parseEx)
            {
                //This indicates a parser error e.g unexpected character, premature end of input, invalid syntax etc.
                Console.WriteLine("Parser Error");
                Console.WriteLine(parseEx.Message);
                return null;
            }
            catch (RdfException rdfEx)
            {
                //This represents a RDF error e.g. illegal triple for the given syntax, undefined namespace
                Console.WriteLine("RDF Error");
                Console.WriteLine(rdfEx.Message);
                return null;
            }
        }


        public void SaveGraphToFile(IGraph g, String fileName)
        {
            if (g == null || fileName.Equals("")) return;

            var writer = new RdfXmlWriter();

            //Set Pretty Print Mode on if supported
            if (writer is IPrettyPrintingWriter)
            {
                ((IPrettyPrintingWriter) writer).PrettyPrintMode = true;
            }

            //Set High Speed Mode forbidden if supported
            if (writer is IHighSpeedWriter)
            {
                ((IHighSpeedWriter) writer).HighSpeedModePermitted = false;
            }

            //Set Compression Level to High if supported
            if (writer is ICompressingWriter)
            {
                ((ICompressingWriter) writer).CompressionLevel = WriterCompressionLevel.High;
            }

            //Save the Graph
            writer.Save(g, fileName);
        }

        public void PrintGraphToConsole(IGraph graph)
        {
            if (graph == null)
            {
                Console.WriteLine(new ArgumentNullException("graph").ToString());
            }
            try
            {
                var rdfxmlwriter = new RdfXmlWriter();
                rdfxmlwriter.Save(graph, Console.Out);
            }
            catch (Exception exc)
            {
                Console.WriteLine(exc.Message.ToString(CultureInfo.InvariantCulture));
            }
        }

        public List<String> TryFindUriNode(IGraph g, string niz)
        {
            ArrayList result = new ArrayList();
            string owlNS = "http://www.semanticweb.org/andraz/ontologies/2014/5/untitled-ontology-26#";

            IUriNode propName = g.CreateUriNode(UriFactory.Create(owlNS + niz));

            IEnumerable triples = g.GetTriplesWithPredicate(propName);

            List<String> list = new List<string>();
            // Sprehodimo se po rezultatih in jih dodamo v seznam
            foreach (Triple t in triples)
            {
                list.Add(t.Object.ToString());
            }
            return list;
        }
        public List<String> TryFindUriNode(IGraph g, string sbuject, string predicate)
        {
            ArrayList result = new ArrayList();
            string owlNS = "http://www.semanticweb.org/andraz/ontologies/2014/5/untitled-ontology-26#";

            IUriNode propName = g.CreateUriNode(UriFactory.Create(owlNS + sbuject));

            IEnumerable triples = g.GetTriplesWithSubjectPredicate(propName, g.CreateUriNode(UriFactory.Create(owlNS + predicate)));

            List<String> list = new List<string>();
            // Sprehodimo se po rezultatih in jih dodamo v seznam
            foreach (Triple t in triples)
            {
                list.Add(t.Object.ToString());
            }
            return list;
        }

        public IGraph FillGraphWithData(IGraph graph, DataContainer data)
        {
            try
            {
                if (graph == null) throw new ArgumentNullException("graph");
                if (data == null) throw new ArgumentNullException("data");

                var url = "~//App_Data//";
                var name = data.ImdbReader.Title;
                name = name.Replace(":", "");
                name = name.Replace("?", "");

                url = HttpContext.Current.Server.MapPath(url + name);

                // Definiramo prefikse, ki jih bomo uporabljali
                string owlNS = "http://www.semanticweb.org/andraz/ontologies/2014/5/untitled-ontology-26#";

                // Naredimo prazen RDF Model
                graph.NamespaceMap.AddNamespace("owl", UriFactory.Create(owlNS));

                // Kreiramo lastnosti, ki jih bomo uporabili
                var Title = graph.CreateUriNode(UriFactory.Create(owlNS + "Title"));
                var ReleaseDate = graph.CreateUriNode(UriFactory.Create(owlNS + "ReleaseDate"));
                var Rating = graph.CreateUriNode(UriFactory.Create(owlNS + "Rating"));
                var Plot = graph.CreateUriNode(UriFactory.Create(owlNS + "Plot"));
                var Duration = graph.CreateUriNode(UriFactory.Create(owlNS + "Duration"));
                var TrailerURL = graph.CreateUriNode(UriFactory.Create(owlNS + "TrailerURL"));
                var ImageUrl = graph.CreateUriNode(UriFactory.Create(owlNS + "ImageUrl"));
                var Wins = graph.CreateUriNode(UriFactory.Create(owlNS + "Wins"));
                var Nomaninations = graph.CreateUriNode(UriFactory.Create(owlNS + "Nomaninations"));
                var Name = graph.CreateUriNode(UriFactory.Create(owlNS + "Name"));
                var Genre = graph.CreateUriNode(UriFactory.Create(owlNS + "Genre"));
                var Awards = graph.CreateUriNode(UriFactory.Create(owlNS + "Awards"));
                var Director = graph.CreateUriNode(UriFactory.Create(owlNS + "Director"));
                var Star = graph.CreateUriNode(UriFactory.Create(owlNS + "Star"));
                var Writer = graph.CreateUriNode(UriFactory.Create(owlNS + "Writer"));
                var Video = graph.CreateUriNode(UriFactory.Create(owlNS + "Video"));


                var rdfType = graph.CreateUriNode("owl:type");

                // Naredimo vir, ki opisuje video
                var obj = graph.CreateUriNode((UriFactory.Create("http://moviesearch.com")));
                // Tvorimo izjavo (trojček), da je video

                graph.Assert(new Triple(obj, rdfType, graph.CreateUriNode(UriFactory.Create(owlNS + "Video"))));
                // Tvorimo trojček, ki opisuje Title 
                graph.Assert(new Triple(Video, Title, graph.CreateLiteralNode(data.ImdbReader.Title)));
                // Tvorimo trojček, ki opisuje RealeseDate 
                graph.Assert(new Triple(Video, ReleaseDate, graph.CreateLiteralNode(data.ImdbReader.ReleaseDate)));
                //RAting
                graph.Assert(new Triple(Video, Rating, graph.CreateLiteralNode(data.ImdbReader.Rating)));
                //Plot
                graph.Assert(new Triple(Video, Plot, graph.CreateLiteralNode(data.ImdbReader.Plot)));
                //Duration
                graph.Assert(new Triple(Video, Duration, graph.CreateLiteralNode(data.ImdbReader.Runtime)));
                //ImageUrl
                 graph.Assert(new Triple(Video, ImageUrl,graph.CreateLiteralNode(data.ImdbReader.PosterLarge)));
                



                //Trailer
                graph.Assert(new Triple(obj, rdfType, graph.CreateUriNode(UriFactory.Create(owlNS + "Trailer"))));
                //TrailerURL
                foreach (var stringUrl in data.YouTubeSource)
                {
                    graph.Assert(new Triple(graph.CreateUriNode(UriFactory.Create(owlNS + "Trailer")), TrailerURL,
                        graph.CreateLiteralNode(stringUrl)));
                }



                //Wins
                graph.Assert(new Triple(obj, rdfType, graph.CreateUriNode(UriFactory.Create(owlNS + "Wins"))));
                //Wins
                graph.Assert(new Triple(graph.CreateUriNode(UriFactory.Create(owlNS + "Wins")), Wins,
                    graph.CreateLiteralNode(data.ImdbReader.Awards)));

                //Nomaninations
                graph.Assert(new Triple(obj, rdfType, graph.CreateUriNode(UriFactory.Create(owlNS + "Nomaninations"))));
                //Nomaninations
                graph.Assert(new Triple(graph.CreateUriNode(UriFactory.Create(owlNS + "Nomaninations")), Nomaninations,
                    graph.CreateLiteralNode(data.ImdbReader.Nominations)));

                //Director
                graph.Assert(new Triple(obj, rdfType, graph.CreateUriNode(UriFactory.Create(owlNS + "Director"))));
                foreach (string director_string in data.ImdbReader.Directors)
                    graph.Assert(new Triple(graph.CreateUriNode(UriFactory.Create(owlNS + "Director")), Name,
                        graph.CreateLiteralNode(director_string)));

                //Star
                graph.Assert(new Triple(obj, rdfType, graph.CreateUriNode(UriFactory.Create(owlNS + "Star"))));
                foreach (string star_string in data.ImdbReader.Cast)
                    graph.Assert(new Triple(graph.CreateUriNode(UriFactory.Create(owlNS + "Star")), Name,
                        graph.CreateLiteralNode(star_string)));

                //Writer
                graph.Assert(new Triple(obj, rdfType, graph.CreateUriNode(UriFactory.Create(owlNS + "Writer"))));
                foreach (string writer_string in data.ImdbReader.Writers)
                    graph.Assert(new Triple(graph.CreateUriNode(UriFactory.Create(owlNS + "Writer")), Name,
                        graph.CreateLiteralNode(writer_string)));

                //Genre
                graph.Assert(new Triple(obj, rdfType, graph.CreateUriNode(UriFactory.Create(owlNS + "Genre"))));
                foreach (String gener_string in data.ImdbReader.Genres)
                    graph.Assert(new Triple(graph.CreateUriNode(UriFactory.Create(owlNS + "Genre")), Genre,
                        graph.CreateLiteralNode(gener_string)));

                //Awards
                graph.Assert(new Triple(obj, rdfType, graph.CreateUriNode(UriFactory.Create(owlNS + "Award"))));
                graph.Assert(new Triple(graph.CreateUriNode(UriFactory.Create(owlNS + "Award")), Awards, graph.CreateLiteralNode(data.ImdbReader.Awards)));


                SaveGraphToFile(graph, url + ".rdf");

                return graph;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            return null;
        }

        public DataTable vrniData(IGraph graph)
        {
            DataTable table = new DataTable();
            table.Columns.Add("Polje");
            table.Columns.Add("Vrednost");

            String[] uris = new String[] {"Title", "ReleaseDate", "Rating", "Plot","Duration", "TrailerURL","Wins","Nomaninations",
            "Genre","Awards","Director","Star", "Writer","ImageUrl" };

            foreach (String uri in uris)
            {
                List<String> list_data = new List<string>();
                if (uri.Equals("Director") || uri.Equals("Star") || uri.Equals("Writer"))
                {
                    list_data = TryFindUriNode(graph, uri, "Name");
                }
                else{
                     list_data = TryFindUriNode(graph, uri);
                }
                if (list_data.Count == 0)
                {

                    table.Rows.Add(uri, "No Data");
                }
                else
                {
                    foreach (String string_data in list_data)
                    {
                        table.Rows.Add(uri, string_data);
                        /*
                        if (string_data != list_data.Last())
                            link_string += string_data + ", ";
                        else
                            link_string += string_data;*/
                    }
                       
                }
            }

            return table;

        }
        private static string GetNodeString(INode node)

        {
            string s = node.ToString();
            switch (node.NodeType)
            {
                case NodeType.Uri:
                    int lio = s.LastIndexOf('#');
                    if (lio == -1)
                        return s;
                    else
                        return s.Substring(lio + 1);
                case NodeType.Literal:
                    return string.Format("\"{0}\"", s);
                default:
                    return s;
            }
        }
    }
}